type EventNameType = string | number | symbol;
type EventCallback = (...args: Array<any>) => any;
type ListenStopHandle = () => void;

class Emitter {
  private eventMap: Map<EventNameType, Array<EventCallback>>;

  constructor() {
    this.eventMap = new Map();
  }

  public on = (name: EventNameType, callback: EventCallback): ListenStopHandle => {

    if (!this.eventMap.has(name)) {
      this.eventMap.set(name, []);
    }

    const callbackList = this.eventMap.get(name);
    callbackList?.push(callback);

    return () => this.off(name, callback);
  }

  public once = (name: EventNameType, callback: EventCallback): ListenStopHandle => {

    const listener = (...args: Array<any>) => {
      this.off(name, listener);
      callback(...args);
    }

    this.on(name, listener);

    return () => this.off(name, listener);
  }

  public emit = (name: EventNameType, ...args: Array<any>): void => {
    const callbackList = this.eventMap.get(name);
    Array.isArray(callbackList) && callbackList.forEach(cb => typeof cb === 'function' && cb(...args));
  }

  public off = (name: EventNameType, callback: EventCallback): void => {
    // 没有name
    if (!name) {
      this.eventMap.clear();
    } 
    // 有name也有callback
    else if (typeof callback === 'function') {
      let callbackList = this.eventMap.get(name);
      if (Array.isArray(callbackList)) {
        callbackList = callbackList.filter(cb => cb !== callback)
        this.eventMap.set(name, callbackList);
      }
    } 
    // 只有name没有callback
    else {
      this.eventMap.delete(name);
    }
  }

}


export {
  EventNameType,
  EventCallback,
  ListenStopHandle,
  Emitter
}